-
Notifications
You must be signed in to change notification settings - Fork 371
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature - Identity verification implementation #2196
Feature - Identity verification implementation #2196
Conversation
a6e4349
to
ff50c7d
Compare
95c6162
to
8931712
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most of my feedback was added inline, but I have one additional comment that wasn't clear if it is TODO yet or not. Is the new JWT endpoint to remove email and SMS by token still TODO in this PR, or did I miss it?
Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/application/MainApplication.java
Outdated
Show resolved
Hide resolved
Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/application/MainApplication.java
Outdated
Show resolved
Hide resolved
Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/model/MainActivityViewModel.java
Outdated
Show resolved
Hide resolved
Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/util/SharedPreferenceUtil.java
Outdated
Show resolved
Hide resolved
OneSignalSDK/onesignal/core/src/main/java/com/onesignal/IUserJwtInvalidatedListener.kt
Outdated
Show resolved
Hide resolved
var jwtToken: String? | ||
get() = getOptStringProperty(IdentityConstants.JWT_TOKEN) | ||
set(value) { | ||
setOptStringProperty(IdentityConstants.JWT_TOKEN, value, ModelChangeTags.NO_PROPOGATE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we want to propagate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Propagating the property will result in a setAlias request. We don't want the change of JWT triggers a setAlias operation.
...lSDK/onesignal/core/src/main/java/com/onesignal/user/internal/identity/IdentityModelStore.kt
Outdated
Show resolved
Hide resolved
...signal/user/internal/operations/impl/executors/LoginUserFromSubscriptionOperationExecutor.kt
Show resolved
Hide resolved
@@ -82,8 +84,10 @@ internal class LoginUserFromSubscriptionOperationExecutor( | |||
return when (responseType) { | |||
NetworkUtils.ResponseStatusType.RETRYABLE -> | |||
ExecutionResponse(ExecutionResult.FAIL_RETRY) | |||
NetworkUtils.ResponseStatusType.UNAUTHORIZED -> | |||
NetworkUtils.ResponseStatusType.UNAUTHORIZED -> { | |||
_identityModelStore.invalidateJwt() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see we call this _identityModelStore.invalidateJwt()
in every executor, do you think it would work out to have the OperationRepo process ExecutionResult.FAIL_UNAUTHORIZED
so it is the only one calling invalidateJwt()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Addressed in the fixup commit. The original plan was to fire the invalidate event for some specific operations instead of any operation. but I just realized UNAUTHORIZED response can only be returned by these specific operations anyway. I just move the invalidation to OperationRepo out of executors.
@@ -160,7 +164,18 @@ internal class LoginUserOperationExecutor( | |||
|
|||
try { | |||
val subscriptionList = subscriptions.toList() | |||
val response = _userBackend.createUser(createUserOperation.appId, identities, subscriptionList.map { it.second }, properties) | |||
val pushSubscription = subscriptions.values.find { it.type == SubscriptionObjectType.ANDROID_PUSH } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This SDK supports fireOS and Huawei push so you will need a more complete check. However, since this looks like it is for Device Auth then we can remove it.
- That is, once we have 100% committed to that path, so hold on addressing this comment until then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only purpose for the pushSubscription is to acquire the push token. Since we are confirmed that we don't need the token for subscription operation, I removed it in the fixup commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you removed the usage of this but this line was not cleaned up.
8931712
to
ffa634a
Compare
…tions that have no valid JWT
ffa634a
to
db78c39
Compare
8e9ae06
to
868d5d4
Compare
Examples/OneSignalDemo/app/src/main/java/com/onesignal/sdktest/model/MainActivityViewModel.java
Outdated
Show resolved
Hide resolved
@@ -72,7 +72,7 @@ internal class ConfigModelStoreListener( | |||
// copy current model into new model, then override with what comes down. | |||
val config = ConfigModel() | |||
config.initializeFromModel(null, _configModelStore.model) | |||
|
|||
config.fetchParamsNotifier = _configModelStore.model.fetchParamsNotifier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see, you are right, I mixed up what was happening here.
After looking at this again this extra event seems unnecessary, as we already have a onModelReplaced
event that can be listen to instead.
...nalSDK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/IOperationRepo.kt
Outdated
Show resolved
Hide resolved
...DK/onesignal/core/src/main/java/com/onesignal/core/internal/operations/impl/OperationRepo.kt
Show resolved
Hide resolved
1b9491f
to
9d70a5c
Compare
...sages/src/test/java/com/onesignal/inAppMessages/internal/backend/InAppBackendServiceTests.kt
Show resolved
Hide resolved
@@ -160,7 +164,18 @@ internal class LoginUserOperationExecutor( | |||
|
|||
try { | |||
val subscriptionList = subscriptions.toList() | |||
val response = _userBackend.createUser(createUserOperation.appId, identities, subscriptionList.map { it.second }, properties) | |||
val pushSubscription = subscriptions.values.find { it.type == SubscriptionObjectType.ANDROID_PUSH } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see you removed the usage of this but this line was not cleaned up.
@@ -72,7 +72,7 @@ internal class ConfigModelStoreListener( | |||
// copy current model into new model, then override with what comes down. | |||
val config = ConfigModel() | |||
config.initializeFromModel(null, _configModelStore.model) | |||
|
|||
config.fetchParamsNotifier = _configModelStore.model.fetchParamsNotifier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the IdentityVerificationService
you created is a correct pattern, however I believe it could have just used onModelReplaced
, instead of needing to introduce fetchParamsNotifier
. Switching to that means less code and follows other patterns.
- However if your
fetchParamsNotifier
handles something I am not seeing let me know, or you feel it is a better pattern here.
OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt
Show resolved
Hide resolved
OneSignalSDK/onesignal/core/src/main/java/com/onesignal/internal/OneSignalImp.kt
Outdated
Show resolved
Hide resolved
9d70a5c
to
e39e8bd
Compare
e39e8bd
to
48f4c9a
Compare
Description
One Line Summary
Implement identity verification functionality to our Android SDK with JWT (JSON Web Token) that manage a specific User, their Subscriptions, and Identities, if enabled using OneSignal dashboard.
Details
Motivation
OneSignal Identity Verification feature only exists today for the Player model and we want to bring this feature to the User Model and gives us an opportunity to switch to a more standard client security model, JWT (JSON Web Token).
For Developers
If identity verification is enabled, all operations requiring identity or authorization must be accompanied by a correct JWT. Developers can use OneSignal.login(external_id, jwt) to set a JWT for a specific user identified by their external ID, or OneSignal.updateUserJwt(external_id, jwt) to update the JWT for that user. Additionally, developers can add a JWTInvalidatedListener by calling OneSignal.addUserJwtInvalidatedListener, allowing them to listen for a JWTInvalidatedEvent triggered when a JWT is invalidated by any operation, and subsequently update the JWT as necessary.
To Help With Review
This PR contains a some major structural changes working around identity verification.
Testing
Unit testing
I have include a testing case that simulate a UNAUTHROIZED error (401, 403) and ensure that the jwt for the specific user is invalidated and the JWTInvalidatedEvent is fired.
Manual testing
Affected code checklist
Checklist
Overview
Testing
Final pass
This change is